/*****************************************************************************************/
/* ECSE 426 - Microprocessor - Fall 2009
/* Lab Project - Includes control for PS/2 (Keyboard)
/* testKEYBOARDmain.C
/* @author: Danny Wu - 260238209 - B.Comp.Eng
/* @author: Han-Sheng Chin - 260209715 - B.Elec.Eng
/* @author: Benoit Gravel - 260230976 - B.Comp.Eng
/* @author: Bradley Thompson - 260224857 - B.Comp.Eng

/* @version: 12.11.15.48
/****************************************************************************************/
#include <msp430x14x.h>

//prototypes
void initKeyboard (void);
//int HostReceive (void) __interrupt[PORT1_VECTOR];
void ParseCode(void);
int DataLine(void);
int ClockLine(void);
char lookupKey(void);

//global variables
int KeyboardState=0;
int KeyboardReceiveBit=0;
int KeyboardDataBuffer;
int BreakSeq =0;
char key;

void initKeyboard (void){
  //initialize keyboard (P1.0 -->CLOCK line, P1.1-->DATA line)
  P1SEL &= 0xCF;                // I/O for P1.4,1.5
  P1DIR &= 0xCF;                // input (P1.4,1.5)
  P1IES = 0x10;                 //Clock interupt on high to low transitions
  P1IE = 0x10;                  //Enable interupts on clock line
  P1IFG = 0x00;                 // Clear interrupt flag
  return ;
}//end initKeyboard

  int HostReceive (void) __interrupt[PORT1_VECTOR]{
  int i;
  int parity;
  int mask;
  char Data;

  switch(KeyboardState){

      case 0: //idle
        if ((DataLine()== 0) ){ //Start Bit
          KeyboardState = 2; //go into HostReceive mode
          KeyboardReceiveBit = 1; //Start Bit received
          KeyboardDataBuffer = 0;
        }
      break;
      
      case 1: //HostSend
        //should never reach here since interupts disabled in HOST SEND
      break;
      
      case 2: //HostReceive (DeviceSend)
        if (KeyboardReceiveBit<= 9){  //if Data bits
          //Data = DataLine()
          //KeyboardDataBuffer += DataLine();
          //KeyboardDataBuffer << 1;
          KeyboardDataBuffer += DataLine()*(2^((KeyboardReceiveBit -1)));
          KeyboardReceiveBit++;
        }
        else if (KeyboardReceiveBit == 10){ //parity bit
          parity=0;
          mask=0;

          for(i=0;i<8;i++){
            mask = 2^i;
            if ((KeyboardDataBuffer & mask) != 0){
              parity++;
            }
          }
          parity = parity%2;
          if( DataLine() != !parity){//if expected parity error
            //TODO : hostSend(_Resend);
            break;
          }
          else{
            KeyboardReceiveBit++;
          }
        }
        else{ //Stop Bit
          if(DataLine()==1){ // if Stop bit on DATA line
            KeyboardReceiveBit = 0;
            KeyboardState = 0;  //go back into iddle state
            ParseCode();
          }
        }
      break;
  }//end switch  
  P1IFG = 0x00;                 // Clear interrupt flag
}//end HostReceive interrupt

//Parses content of KeyboardDataBuffer
void ParseCode(void){
   key = lookupKey();  
  if (BreakSeq == '1'){//this key was released
    BreakSeq = 0;    
  }
  else{//this key was pressed
    if (KeyboardDataBuffer == 0xF0){//Break code
      BreakSeq = 1; //signal BreakCode for next key
    }
    else if (key != 0){
      key =key;//TODO print key;
    }
  }
}




//Helper function returns DataLine input
int DataLine(void){
  if((P1IN & 0x20)== 0x00)
    return 0;
  else
    return 1;
}
//Helper function returns ClockLine input
int ClockLine(void){
  if((P1IN & 0x10)== 0x00)
    return 0;
  else
    return 1;
}

//Lookup table for Keyboard ScanCode --> ACSII char
char lookupKey(void){
  switch(KeyboardDataBuffer){
    case(0x0E): return '~';
    case(0x16): return '1';
    case(0x1E): return '2';
    case(0x26): return '3';
    case(0x25): return '4';
    case(0x2E): return '5';
    case(0x36): return '6';
    case(0x3D): return '7';
    case(0x3E): return '8';
    case(0x46): return '9';
    case(0x45): return '0';
    case(0x4E): return '-';
    case(0x15): return 'Q';
    case(0x1D): return 'W';
    case(0x24): return 'E';
    case(0x2D): return 'R';
    case(0x2C): return 'T';
    case(0x35): return 'Y';
    case(0x3C): return 'U';
    case(0x43): return 'I';
    case(0x44): return 'O';
    case(0x4D): return 'P';
    case(0x54): return '[';
    case(0x5B): return ']';
    case(0x1C): return 'A';
    case(0x1B): return 'S';
    case(0x23): return 'D';
    case(0x2B): return 'F';
    case(0x34): return 'G';
    case(0x33): return 'H';
    case(0x3B): return 'J';
    case(0x42): return 'K';
    case(0x4B): return 'L';
    case(0x1A): return 'Z';
    case(0x22): return 'X';
    case(0x21): return 'C';
    case(0x2A): return 'V';
    case(0x32): return 'B';
    case(0x31): return 'N';
    case(0x3A): return 'M';
    case(0x41): return ',';
    case(0x49): return '.';
    case(0x4A): return '/';
    case(0x29): return ' ';//SPACE
    //added
    case(0x5A): return '\n'; //ENTER
    //case(0x76): return 'ESC'; //ESCAPE
    //case(0x66): return 'BS'; //Backspace
    default: return  0;//NULL
  }//end switch
}



void main(void){
  //initialize configuration of the clock
  WDTCTL = WDTPW + WDTHOLD;             // Stop WDT
  BCSCTL1 &= ~XT2OFF;                   // XT2OFF
  BCSCTL2 |= SELS;                      // MCLK = SMCLK = XT2 (safe)
  _EINT();                              // Enable interrupts
  
  initKeyboard();
  while(1);
}
